#ifndef TRANSFORM2_H
#define TRANSFORM2_H

#include "Matrix2.h"
#include "Matrix4.h"

namespace p2 {

template<typename Real>
class Transform2
{
public:

	inline Transform2()
	{
		setIdentity();
	}
    
	inline Transform2(Transform2<Real> const& transform)
	{
		_translation = transform._translation;
        _rotation = transform._rotation;
		_scale = transform._scale;
		update();
	}
    
	inline Transform2(Vector2<Real> translation, Matrix2<Real> rotation, Vector2<Real> scale)
	:	_translation(translation), _rotation(rotation), _scale(scale)
	{
		update();
	}

	inline Transform2(Vector2<Real> translation, Real radians, Vector2<Real> scale)
	:	_translation(translation), _scale(scale)
	{
		_rotation.makeRotation(radians);
		update();
	}

    virtual ~Transform2()
	{
	}

	void setIdentity()
	{
		_rotation.makeIdentity();
		_translation = Vector2<Real>::ZERO;
		_scale = Vector2<real>(1.f, 1.f);
		update();
	}

	/*
	 * access
	 */
	Vector2<Real> const& getTranslation() const
	{
		return _translation;
	}
	void setTranslation(Vector2<Real> const& translation)
	{
		_translation = translation;
		update();
	}
	Matrix2<Real> const& getRotation() const
	{
		return _rotation;
	}
	void setAngle(Real radians)
	{
		_rotation.makeRotation(radians);
		update();
	}
	Vector2<Real> const& getScale() const
	{
		return _scale;
	}
	void setScale(Vector2<Real> s)
	{
		_scale = s;
		update();
	}
	Matrix4<Real> const& getMatrix() const
	{
		return _matrix;
	}

	/*
	 * operations
	 */
	inline Vector2<Real> translate(Vector2<Real> v) const
	{
		return _translation + v;
	}
	inline Vector2<Real> translateIntoLocalSpace(Vector2<Real> v) const
	{
		return v - _translation;
	}

	inline Vector2<Real> rotate(Vector2<Real> v) const
	{
		return v * _rotation;
	}
	inline Vector2<Real> rotateIntoLocalSpace(Vector2<Real> v) const
	{
		return _rotation * v;
	}
	
	inline Vector2<Real> transform(Vector2<Real> v) const
	{
		return translate(rotate(v));
	}

    inline Vector2<Real> transformIntoLocalSpace(Vector2<Real> v) const
	{
		return rotateIntoLocalSpace(translateIntoLocalSpace(v));
	}

private:
	void update()
	{
		_matrix = Matrix4<real>(
			_scale.X() * _rotation[0][0], _scale.X() * _rotation[0][1], (real)0, (real)0,
			_scale.Y() * _rotation[1][0], _scale.Y() * _rotation[1][1], (real)0, (real)0,
			(real)0, (real)0, (real)1, (real)0,
			_translation.X(), _translation.Y(), (real)0, (real)1
		);
	}

private:
	Vector2<Real> _translation;
	Matrix2<Real> _rotation;
	Vector2<Real> _scale;
	/*
	 * the internal matrix cannot be manipulated other than by using
	 * set methods for the above data members
	 */
	Matrix4<Real> _matrix;
};

}

#endif	//TRANSFORM2_H
